
/*
 * Copyright (c) 2008, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package ensemble.pages;

import ensemble.*;
import ensemble.model.SampleInfo;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.animation.TimelineBuilder;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.text.TextAlignment;
import javafx.util.Duration;

/**
 * SamplePage
 */
public class SamplePage extends Page {

    private SampleInfo sampleInfo;
    private Class sampleClass;

    public SamplePage(String name, String sourceFileUrl) throws IllegalArgumentException {
        super(name);
        String unqualifiedClassName = sourceFileUrl.substring(sourceFileUrl.lastIndexOf('/') + 1,
                sourceFileUrl.length() - 5);
        try {
            // load src into String
            StringBuilder builder = new StringBuilder();
            URI uri = new URI(sourceFileUrl);
            InputStream in = uri.toURL().openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
                builder.append('\n');
            }
            reader.close();
            // parse sample info
            sampleInfo = new SampleInfo(sourceFileUrl, unqualifiedClassName, builder.toString());
            // load class
            sampleClass = getClass().getClassLoader().loadClass(sampleInfo.getClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public SamplePage(SamplePage pageToClone) {
        super(pageToClone.getName());
        this.sampleInfo = pageToClone.sampleInfo;
        this.sampleClass = pageToClone.sampleClass;
    }

    public SampleInfo getSampleInfo() {
        return sampleInfo;
    }

    @Override
    public Node createView() {
        // check if 3d sample and on supported platform
        //System.out.println("sampleClass.getSuperclass() == Sample3D.class = " + (sampleClass.getSuperclass() == Sample3D.class));
        //System.out.println("Platform.isSupported(ConditionalFeature.SCENE3D) = " + Platform.isSupported(ConditionalFeature.SCENE3D));
        if (sampleClass.getSuperclass() == Sample3D.class && !Platform.isSupported(ConditionalFeature.SCENE3D)) {
            Label error = new Label("JavaFX 3D is currently not supported on your configuration.");
            error.setStyle("-fx-text-fill: orangered; -fx-font-size: 1.4em;");
            error.setWrapText(true);
            error.setAlignment(Pos.CENTER);
            error.setTextAlignment(TextAlignment.CENTER);
            return error;
        }

        try {
            // create main grid
            //final FlowSafeVBox main = new FlowSafeVBox();
            final VBox main = new VBox(8);
            main.getStyleClass().add("sample-page");
            // create header
            Label header = new Label(getName());
            header.getStyleClass().add("page-header");
            main.getChildren().add(header);
            // create sample area
            final StackPane sampleArea = new StackPane();
            VBox.setVgrow(sampleArea, Priority.SOMETIMES);
            main.getChildren().add(sampleArea);
            // create sample
            final Sample sample = (Sample) sampleClass.newInstance();
            sampleArea.getChildren().add(sample);
            
            // create sample controls
            Node sampleControls = sample.getControls();
            if (sampleControls != null) {
                Label subHeader = new Label("Play with these:");
                subHeader.getStyleClass().add("page-subheader");
                main.getChildren().add(subHeader);
                main.getChildren().add(sampleControls);
            }

            // create border pane for main content and sidebar
            BorderPane borderPane = new BorderPane();
            borderPane.setCenter(main);
            //borderPane.setRight(createSideBar(sample));
            ScrollPane scrollPane = new ScrollPane();
            scrollPane.getStyleClass().add("noborder-scroll-pane");
            scrollPane.setContent(borderPane);
            scrollPane.setFitToWidth(true);
            scrollPane.setFitToHeight(true);
            scrollPane.setMinWidth(725);
            return scrollPane;
        } catch (Exception e) {
            e.printStackTrace();
            return new Text("Failed to create sample because of [" + e.getMessage() + "]");
        }
    }

    private Node getIcon() {
        URL url = sampleClass.getResource(sampleClass.getSimpleName() + ".png");
        if (url != null) {
            ImageView imageView = new ImageView(new Image(url.toString()));
            return imageView;
        } else {
            ImageView imageView = new ImageView(new Image(Ensemble2.class.getResource("images/icon-overlay.png").toString()));
            imageView.setMouseTransparent(true);
            Rectangle overlayHighlight = new Rectangle(-8, -8, 130, 130);
            overlayHighlight.setFill(new LinearGradient(0, 0.5, 0, 1, true, CycleMethod.NO_CYCLE, new Stop[]{new Stop(0, Color.BLACK), new Stop(1, Color.web("#444444"))}));
            overlayHighlight.setOpacity(0.8);
            overlayHighlight.setMouseTransparent(true);
            overlayHighlight.setBlendMode(BlendMode.ADD);
            Rectangle background = new Rectangle(-8, -8, 130, 130);
            background.setFill(Color.web("#b9c0c5"));
            Group group = new Group(background);
            Rectangle clipRect = new Rectangle(114, 114);
            clipRect.setArcWidth(38);
            clipRect.setArcHeight(38);
            group.setClip(clipRect);
            Node content = createIconContent();
            if (content != null) {
                content.setTranslateX((int) ((114 - content.getBoundsInParent().getWidth()) / 2) - (int) content.getBoundsInParent().getMinX());
                content.setTranslateY((int) ((114 - content.getBoundsInParent().getHeight()) / 2) - (int) content.getBoundsInParent().getMinY());
                group.getChildren().add(content);
            }
            group.getChildren().addAll(overlayHighlight, imageView);
            // Wrap in extra group as clip dosn't effect layout without it
            return new Group(group);
        }
    }

    public Node createIconContent() {
        try {
            Method createIconContent = sampleClass.getDeclaredMethod("createIconContent");
            return (Node) createIconContent.invoke(sampleClass);
        } catch (NoSuchMethodException e) {
            System.err.println("Sample [" + getName() + "] is missing a icon.");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Node createTile() {
        Button tile = new Button(getName().trim(), getIcon());
        tile.setMinSize(140, 145);
        tile.setPrefSize(140, 145);
        tile.setMaxSize(140, 145);
        tile.setContentDisplay(ContentDisplay.TOP);
        tile.getStyleClass().clear();
        tile.getStyleClass().add("sample-tile");
        tile.setOnAction(new EventHandler() {
            public void handle(Event event) {
                Ensemble2.getEnsemble2().goToPage(SamplePage.this);
            }
        });
        return tile;
    }

    public static class SamplePageView extends TabPane {

        private Sample sample;

        public SamplePageView(Sample sample) {
            super();
            this.sample = sample;
        }

        public void stop() {
            sample.stop();
        }
    }
}
